home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue55 / Alfresco / AAThread.pas next >
Encoding:
Pascal/Delphi Source File  |  2000-02-10  |  5.4 KB  |  200 lines

  1. {*********************************************************}
  2. {* AAThread                                              *}
  3. {* Copyright (c) Julian M Bucknall 1998-2000             *}
  4. {* All rights reserved.                                  *}
  5. {*********************************************************}
  6. {* Algorithms Alfresco threading stuff                   *}
  7. {*********************************************************}
  8.  
  9. {Note: this unit is released as freeware. In other words, you are free
  10.        to use this unit in your own applications, however I retain all
  11.        copyright to the code. JMB}
  12.  
  13. unit AAThread;
  14.  
  15. interface
  16.  
  17. {$IFNDEF Win32}
  18. !! Error - this unit is for 32-bit Windows only
  19. {$ENDIF}
  20.  
  21. uses
  22.   Windows, SysUtils;
  23.  
  24. type
  25.   TaaReadWriteSync = class
  26.     private
  27.       FBlockedReaders : THandle; {a semaphore}
  28.       FBlockedWriters : THandle; {a semaphore}
  29.       FController     : THandle; {a mutex}
  30.       FActiveReaders  : integer;
  31.       FActiveWriter   : boolean;
  32.       FWaitingReaders : integer;
  33.       FWaitingWriters : integer;
  34.     protected
  35.     public
  36.       constructor Create;
  37.       destructor Destroy; override;
  38.  
  39.       procedure StartReading;
  40.       procedure StartWriting;
  41.       procedure StopReading;
  42.       procedure StopWriting;
  43.   end;
  44.  
  45. implementation
  46.  
  47. {===Helper routines==================================================}
  48. procedure RandomSyncObjName(aDest : PChar; const aRootName : string);
  49. var
  50.   Len : integer;
  51.   i   : integer;
  52. begin
  53.   Len := length(aRootName);
  54.   StrCopy(aDest, PChar(aRootName));
  55.   inc(aDest, Len);
  56.   aDest^ := '/';
  57.   inc(aDest);
  58.   for i := 1 to 10 do begin
  59.     aDest^ := chr(Random(26) + ord('A'));
  60.     inc(aDest);
  61.   end;
  62.   aDest^ := #0;
  63. end;
  64. {====================================================================}
  65.  
  66.  
  67. {====================================================================}
  68. constructor TaaReadWriteSync.Create;
  69. var
  70.   NameZ : array [0..MAX_PATH] of char; 
  71. begin
  72.   inherited Create;
  73.   {create the primitive synchronization objects}
  74.   RandomSyncObjName(NameZ, 'aaRW.BlockedReaders');
  75.   FBlockedReaders := CreateSemaphore(nil, 0, 127, NameZ);
  76.   RandomSyncObjName(NameZ, 'aaRW.BlockedWriters');
  77.   FBlockedWriters := CreateSemaphore(nil, 0, 1, NameZ);
  78.   RandomSyncObjName(NameZ, 'aaRW.Controller');
  79.   FController := CreateMutex(nil, false, NameZ);
  80. end;
  81. {--------}
  82. destructor TaaReadWriteSync.Destroy;
  83. begin
  84.   CloseHandle(FBlockedReaders);
  85.   CloseHandle(FBlockedWriters);
  86.   CloseHandle(FController);
  87.   inherited Destroy;
  88. end;
  89. {--------}
  90. procedure TaaReadWriteSync.StartReading;
  91. var
  92.   HaveToWait : boolean;
  93. begin
  94.   {acquire the controlling mutex}
  95.   WaitForSingleObject(FController, INFINITE);
  96.  
  97.   {if there is a writer executing or there is at least one writer
  98.    waiting, add ourselves as a waiting reader, make sure we wait}
  99.   if FActiveWriter or (FWaitingWriters <> 0) then begin
  100.     inc(FWaitingReaders);
  101.     HaveToWait := true;
  102.   end
  103.  
  104.   {otherwise, add ourselves as another executing reader, and make sure
  105.    we don't wait}
  106.   else begin
  107.     inc(FActiveReaders);
  108.     HaveToWait := false;
  109.   end;
  110.  
  111.   {release the controlling mutex}
  112.   ReleaseMutex(FController);
  113.  
  114.   {if we have to wait, then do so}
  115.   if HaveToWait then
  116.     WaitForSingleObject(FBlockedReaders, INFINITE);
  117. end;
  118. {--------}
  119. procedure TaaReadWriteSync.StartWriting;
  120. var
  121.   HaveToWait : boolean;
  122. begin
  123.   {acquire the controlling mutex}
  124.   WaitForSingleObject(FController, INFINITE);
  125.  
  126.   {if there are readers or another writer running, add ourselves as a
  127.    waiting writer, and make sure we wait}
  128.   if FActiveWriter or (FActiveReaders <> 0) then begin
  129.     inc(FWaitingWriters);
  130.     HaveToWait := true;
  131.   end
  132.  
  133.   {otherwise, add ourselves as another executing writer, and make sure
  134.    we don't wait}
  135.   else begin
  136.     FActiveWriter := true;
  137.     HaveToWait := false;
  138.   end;
  139.  
  140.   {release the controlling mutex}
  141.   ReleaseMutex(FController);
  142.  
  143.   {if we have to wait, then do so}
  144.   if HaveToWait then
  145.     WaitForSingleObject(FBlockedWriters, INFINITE);
  146. end;
  147. {--------}
  148. procedure TaaReadWriteSync.StopReading;
  149. begin
  150.   {acquire the controlling mutex}
  151.   WaitForSingleObject(FController, INFINITE);
  152.  
  153.   {we're finishing reading}
  154.   dec(FActiveReaders);
  155.  
  156.   {if we are the last reader in this cycle, and there is at least one
  157.    writer waiting, release it}
  158.   if (FActiveReaders = 0) and (FWaitingWriters <> 0) then begin
  159.     dec(FWaitingWriters);
  160.     FActiveWriter := true;
  161.     ReleaseSemaphore(FBlockedWriters, 1, nil);
  162.   end;
  163.  
  164.   {release the controlling mutex}
  165.   ReleaseMutex(FController);
  166. end;
  167. {--------}
  168. procedure TaaReadWriteSync.StopWriting;
  169. var
  170.   i : integer;
  171. begin
  172.   {acquire the controlling mutex}
  173.   WaitForSingleObject(FController, INFINITE);
  174.  
  175.   {we're finishing writing}
  176.   FActiveWriter := false;
  177.  
  178.   {if there is at least one reader waiting, release them all}
  179.   if (FWaitingReaders <> 0) then begin
  180.     for i := pred(FWaitingReaders) downto 0 do begin
  181.       dec(FWaitingReaders);
  182.       inc(FActiveReaders);
  183.       ReleaseSemaphore(FBlockedReaders, 1, nil);
  184.     end;
  185.   end
  186.  
  187.   {otherwise, if there is at least one waiting writer, release one}
  188.   else if (FWaitingWriters <> 0) then begin
  189.     dec(FWaitingWriters);
  190.     FActiveWriter := true;
  191.     ReleaseSemaphore(FBlockedWriters, 1, nil);
  192.   end;
  193.  
  194.   {release the controlling mutex}
  195.   ReleaseMutex(FController);
  196. end;
  197. {====================================================================}
  198.  
  199. end.
  200.